#include "IHardwareInterface.h"
#include "SerialMessageQueueManager.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <map>
#include <vector>

class ESP32Hardware : public IHardwareInterface {
public:
	ESP32Hardware() {
		// 创建并启动串口消息队列
		m_serial_queue = new SerialMessageQueueManager();
		m_serial_queue->startConsumer([](Message msg) {
			// 所有给串口发数据都要从这里来
			uart_write_bytes((uart_port_t)ESP32Hardware::PORT_NUM_MAP[msg.port_num], msg.payload, msg.length);
		});
	}
	~ESP32Hardware() {}
	// 注册串口回调
	bool onSerialData(uart_serial_port_t *config) override {
		int map_port = ESP32Hardware::PORT_NUM_MAP[config->port_number];
		// 如果该串口还没有任务，就创建任务
		if (tasks.find(map_port) != tasks.end()) {
			return false;
		}

		int rxPin = GPIO_NUM_NC;
		int txPin = GPIO_NUM_NC;
		if (map_port == 0) {
			rxPin = GPIO_NUM_1;
			txPin = GPIO_NUM_3;
		} else if (map_port == 1) {
			rxPin = GPIO_NUM_16;
			txPin = GPIO_NUM_17;
		} else if (map_port == 2) {
			rxPin = GPIO_NUM_32;
			txPin = GPIO_NUM_33;
		}

		callbacks[map_port] = config->callback;
		uart_port_t uart_port_num = (uart_port_t)map_port;

		uart_config_t uart_config = {
			.baud_rate = full_baud_rate[config->baud_rate],
			.data_bits = mapDataBit(config->data_bits),
			.parity = mapParity(config->parity),
			.stop_bits = static_cast<uart_stop_bits_t>(config->stop_bits),
		};

		if (uart_param_config(uart_port_num, &uart_config) != ESP_OK) {
			return false;
		}

		if (uart_set_pin(uart_port_num, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE) != ESP_OK) {
			return false;
		}

		if (uart_driver_install(uart_port_num, 1024, 0, 0, NULL, 0) != ESP_OK) {
			return false;
		}

		BaseType_t res = xTaskCreate(
			uartTaskWrapper,
			"uartTask",
			4096,
			this,
			10,
			&tasks[map_port]);
		if (res != pdPASS) {
			printf("Failed to create UART task for port %d\n", map_port);
		}
		return true;
	}

	bool writeSerial(int portNumber, char *data, size_t length) override {
		Message msg = {
			.port_num = portNumber,
			.payload = data,
			.length = length,
		};
		return m_serial_queue->send(msg);
	}

	int readPin(int pinNumber) override {
		return gpio_get_level((gpio_num_t)pinNumber);
	}

	bool writePin(int pinNumber, int value) override {
		gpio_set_level((gpio_num_t)pinNumber, value);
		return true;
	}

private:
	std::map<int, Callback<void, std::vector<char>>> callbacks;
	std::map<int, TaskHandle_t> tasks;

	// 每个串口独立任务
	static void uartTaskWrapper(void *arg) {
		ESP32Hardware *self = static_cast<ESP32Hardware *>(arg);

		// 获取创建任务时传入的任务句柄对应的 portNumber
		int portNumber = -1;
		TaskHandle_t handle = xTaskGetCurrentTaskHandle();
		for (auto &p : self->tasks) {
			if (p.second == handle) {
				portNumber = p.first;
				break;
			}
		}

		if (portNumber < 0) {
			printf("Cannot find port number for task!\n");
			vTaskDelete(nullptr);
			return;
		}

		uint8_t buf[256];

		while (true) {
			int len = uart_read_bytes((uart_port_t)portNumber, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
			if (len > 0) {
				if (self->callbacks.count(portNumber)) {
					std::vector<char> data(buf, buf + len);
					self->callbacks[portNumber].callCallback(data);
				}
			}
			vTaskDelay(10 / portTICK_PERIOD_MS); // 防止 CPU 占用过高
		}
	}

	uart_parity_t mapParity(uint8_t platformParity) {
		switch (platformParity) {
		case 0:
			return UART_PARITY_DISABLE;
		case 1:
			return UART_PARITY_ODD;
		case 2:
			return UART_PARITY_EVEN;
		default:
			return UART_PARITY_DISABLE; // 默认安全
		}
	}

	uart_word_length_t mapDataBit(uint8_t dataBit) {
		switch (dataBit) {
		case 5:
			return UART_DATA_5_BITS;
		case 6:
			return UART_DATA_6_BITS;
		case 7:
			return UART_DATA_7_BITS;
		case 8:
			return UART_DATA_8_BITS;
		default:
			return UART_DATA_BITS_MAX;
		}
	}
	/**
	 * 端口映射，隐藏串口0不允许使用（日志串口）
	 * 平台配置的0号端口，在这里映射为1号，依次类推
	 * 其它：平台只要求配置1和2号端口，至于固件到底开了那个端口由开发者决定，只需要实现1和2号端口即可.
	 */
	constexpr static int PORT_NUM_MAP[2] = {1, 2};
	int full_baud_rate[13] = {1200, 2400, 9600, 10400, 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, 921600};
	SerialMessageQueueManager *m_serial_queue;
};
